/*
 * ﻿Copyright (C) 2012 NewMain Softech
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package com.newmainsoftech.ant.taskdefs;

import java.util.List;

import org.apache.tools.ant.taskdefs.optional.junit.JUnitTask;
import org.apache.tools.ant.types.CommandlineJava;
import org.apache.tools.ant.types.Environment.Variable;

import com.newmainsoftech.ant.types.ArgumentExtContract;
import com.newmainsoftech.ant.types.CommandlineJavaExt;
import com.newmainsoftech.ant.types.SysPropExt;

/**
 * Wrapper of Ant's {@link JUnitTask} class to allow multi-line arguments for JVM and system property. <br />
 * <ul>
 * <li><h3>Usage example</h3>
 * <b>Use <code>junitext</code> tag</b> in Ant's <code>target</code> tag (what can be defined in 
 * <code>configuration</code> tag of manve-antrun-plugin's <code>execution</code> tag as well 
 * as in an Ant file).
 * <ul>
 * <li><b>To use multi-line arguments</b>
 * <ul>
 * <li><b>For JVM arguments, use <code>jvmargext</code> tag</b>
 * <blockquote>
 * <code>
 * &lt;<b>junitext</b>&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;<b>jvmargext</b>&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Xmx768m -Xss4M<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Xdebug<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${debug_port}<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;/jvmargext&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;...<br />
 * &lt;/javaext&gt;<br />
 * </code><br />
 * This <code>jvmargext</code> tag is equivalent of:<br />
 * <code>
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;jvmarg value=&quot;-Xmx768m&quot; /&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;jvmarg value=&quot;-Xss4M&quot; /&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;jvmarg value=&quot;-Xdebug /&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;jvmarg <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value=&quot;-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=${debug_port} /&gt;<br />
 * </code> 
 * </blockquote>
 * </li>
 * <li><b>For system properties, use <code>syspropext</code> tag</b>
 * <blockquote>
 * <code>
 * &lt;<b>junitext</b>&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;<b>syspropext</b>&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gwt.args=-standardsMode -war ${war_dir} -logLevel WARN<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.awt.headless=true<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gwt.devjar=${com.google.gwt:gwt-dev:jar}<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.util.logging.config.file=test/com/inetools/gwetons/client/devModeTest.logging.properties<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;/syspropext&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;...<br />
 * &lt;/javaext&gt;<br />
 * </code><br />
 * This <code>syspropext</code> tag is equivalent of:<br />
 * <code>
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;sysproperty <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key=&quot;gwt.args&quot; <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value=&quot;-standardsMode -war ${war_dir} -logLevel WARN&quot; /&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;sysproperty key=&quot;java.awt.headless&quot; value=&quot;true&quot; /&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;sysproperty key=&quot;gwt.devjar&quot; value=&quot;${com.google.gwt:gwt-dev:jar}&quot; /&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&lt;sysproperty <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;key=&quot;java.util.logging.config.file&quot; <br /> 
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value=&quot;test/com/inetools/gwetons/client/devModeTest.logging.properties&quot; /&gt;<br />
 * </code> 
 * </blockquote>
 * </li>
 * </ul>
 * <b>Usage note</b>:
 * <ul>
 * <li>Only one <code>jvmargext</code> tag is supported within single <code>junitext</code> tag. <br />
 * </li>
 * <li>Each argument is extracted as delimited by white space(s) except the case that argument value 
 * containing space(s) is surrounded by double quotation characters.
 * </li>
 * <li>As shown in the above examples, it also resolves <u>${property_name_or_reference_id} 
 * token</u> in each line in multiple-line arguments to actual value. Regarding that, please be advised 
 * the following points:
 * <ul>
 * <li>Such expression will be <u>resolved to actual string value even the expression is inside of 
 * surrounding quotation characters</u>.
 * </li>
 * <li>Effort of <u>resolving property name and reference name</u> to actual value will 
 * <u>be occurred recursively</u>.<br />
 * So, take the jvmargext example above, all arguments could be defined in single property 
 * (let's say jvmargprop for now) then the text content of the jvmargext tag could be simply 
 * stated as below and the ${debug_port} property expression would still be resolved to actual 
 * debug port value. 
 * <blockquote>
 * <code>
 * &lt;jvmargext&gt;<br />
 * &nbsp;&nbsp;&nbsp;&nbsp;${jvmargext}<br />
 * &lt;/jvmargext&gt;<br />
 * </code> 
 * </blockquote>
 * </li>
 * </ul>
 * </li>
 * </ul>  
 * </li>
 * </ul>
 * </li>
 * 
 * <li><h3>Configuration</h3>
 * <ol>
 * <li>Define <code>path</code> tag for this project's archive ant-util.jar file and sub-dependencies.
 * <ul>
 * <li>In the case of using maven-antrun-plugin, you can define com.newmainsoftech:ant-util:jar 
 * and JUnit jar as a dependency of maven-antrun-plugin. Then you can do like below.<br />
 * <blockquote>
 * <code>
 * &lt;property <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;name=&quot;plugin_classpath&quot; <br /> 
 * &nbsp;&nbsp;&nbsp;&nbsp;refid=&quot;maven.plugin.classpath&quot; /&gt;<br />
 * &lt;path id=&quot;antutil_path&quot; <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;path=&quot;${plugin_classpath}&quot; /&gt;
 * </code>
 * </blockquote>
 * </li>
 * <li>If you cannot define com.newmainsoftech:ant-util:jar as a dependency of maven-antrun-plugin 
 * in project's pom.xml, or the case of stand alone Ant environment, then you need to provide path to 
 * com.newmainsoftech:ant-util:jar, org.apache.ant:ant-junit:jar, org.apache.ant:ant-junit4:jar, 
 * and junit:junit:jar. And define <code>path</code> tag with that path:
 * <blockquote>
 * <code>&lt;path id=&quot;antutil_path&quot; <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;path=&quot;${lengthy_path_to_antutil_and_junit_related_jars}&quot; /&gt;</code>
 * </blockquote>
 * </li>
 * </ul>
 * </li>
 * <li>Define <code>taskdef</code> tag for the ant-util's antlib.xml
 * <blockquote>
 * <code>
 * &lt;taskdef <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;resource=&quot;com/newmainsoftech/ant/antlib.xml&quot; <br />
 * &nbsp;&nbsp;&nbsp;&nbsp;classpathref=&quot;antutil_path&quot; /&gt;
 * </code>
 * </blockquote>
 * </li>
 * </ol>
 * </li>
 * </ul>
 * 
 * @author <a href="mailto:artymt@gmail.com">Arata Y.</a>
 * @see SysPropExt
 */
public class JUnitTaskExt extends JUnitTask {
	/**
	 * Explicit constructor since {@link JUnitTask} constructor defined throwing exception. 
	 *  
	 * @throws Exception
	 */
	public JUnitTaskExt() throws Exception {
		super();
	}
	
	/**
	 * To add system property parameters to command line being used at execution of JUnit.
	 * 
	 * @param sysPropExt
	 */
	public void addConfiguredSysPropExt( SysPropExt sysPropExt) {
		List<Variable> propertyList = sysPropExt.getEnvVarList();
		CommandlineJava commandlineJava = getCommandline();
		for( Variable evnVar : propertyList) {
			commandlineJava.addSysproperty( evnVar);
		} // for
	}
	
	CommandlineJavaExt commandlineJavaExt = new CommandlineJavaExt();
	{
    	commandlineJavaExt.setClassname( 
    			"org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
	};
	
	@Override
    protected CommandlineJava getCommandline() {
        return commandlineJavaExt;
    }
	
    public ArgumentExtContract createJvmargext() {
        return ((CommandlineJavaExt)getCommandline()).createVmargext();
    }
}